#!/usr/bin/env python3
# -*- coding: utf-8 -*-
##############################################
# @Author: DengLibin 榆霖
# @Date: Create in 2022-03-03 11:19:24
# @Description: 
##############################################
'继承和多态'
__author__ = 'DengLibin'


# 在OOP程序设计中，当我们定义一个class的时候，可以从某个现有的class继承，新的class称为子类（Subclass），而被继承的class称为基类、父类或超类（Base class、Super class）。

# 比如，我们已经编写了一个名为Animal的class，有一个run()方法可以直接打印：


class Animal(object):
    def run(self):
        print('Animal is running...')

# 当我们需要编写Dog和Cat类时，就可以直接从Animal类继承：
class Dog(Animal):
    def __init__(self, name) -> None:
       self.__name = name
    def run(self):
        super().run()
        print('Dog %s is running...' % self.__name)
        
# 当子类和父类都存在相同的run()方法时，我们说，子类的run()覆盖了父类的run()，
# 在代码运行的时候，总是会调用子类的run()。这样，我们就获得了继承的另一个好处：多态。

# 对于一个变量，我们只需要知道它是Animal类型，无需确切地知道它的子类型，就可以放心地调用run()方法，
# 而具体调用的run()方法是作用在Animal、Dog、Cat还是Tortoise对象上，由运行时该对象的确切类型决定，这就是多态真正的威力：
# 调用方只管调用，不管细节，而当我们新增一种Animal的子类时，只要确保run()方法编写正确，不用管原来的代码是如何调用的。这就是著名的“开闭”原则：
def run_twice(animal):
    animal.run()
    animal.run()


# 静态语言 vs 动态语言
# 对于静态语言（例如Java）来说，如果需要传入Animal类型，则传入的对象必须是Animal类型或者它的子类，否则，将无法调用run()方法。

# 对于Python这样的动态语言来说，则不一定需要传入Animal类型。我们只需要保证传入的对象有一个run()方法就可以了
# 这就是动态语言的“鸭子类型”，它并不要求严格的继承体系，一个对象只要“看起来像鸭子，走起路来像鸭子”，那它就可以被看做是鸭子。


if __name__ == '__main__':
    c = Dog('旺财')
    c.run()
    
    # 多态，Dog可以看成Animal，但Animal不可以看成Dog。
    print(isinstance(c, Animal)) # True
    print(isinstance(c, Dog)) # True
    
    run_twice(c)
    
    
# 小结
# 继承可以把父类的所有功能都直接拿过来，这样就不必重零做起，子类只需要新增自己特有的方法，也可以把父类不适合的方法覆盖重写。

# 动态语言的鸭子类型特点决定了继承不像静态语言那样是必须的。